﻿//  Copyright (c) 2011 Ray Liang (http://www.dotnetage.com)
//  Dual licensed under the MIT and GPL licenses:
//  http://www.opensource.org/licenses/mit-license.php
//  http://www.gnu.org/licenses/gpl.html

using System;
using System.Collections.Generic;
using System.Linq;
using DNA.OpenAPI.OpenSearch;
using System.Web.Mvc;

namespace DNA.Mvc.Searching
{
    public class SearchEngine
    {
        public SearchEngine(IEnumerable<OpenSearchProvider> searchProviders) 
        {
            if (searchProviders == null) 
                throw new ArgumentNullException("searchProviders");
            var providerList = searchProviders.ToList();
            providers = new Dictionary<string, OpenSearchProvider>();

            foreach (var _provider in providerList)
            {
                if (!string.IsNullOrEmpty(_provider.Name) && (!providers.ContainsKey(_provider.Name)))
                    providers.Add(_provider.Name, _provider);
            }
        }

        public Dictionary<string, OpenSearchProvider> providers = null;

        public Dictionary<string, OpenSearchProvider> Providers
        {
            get
            {
                return providers;
            }
        }

        public OpenSearchAtomResult Search(string providerName, string searchTerms, int pageIndex, int pageSize)
        {
            if (string.IsNullOrEmpty(providerName))
                throw new ArgumentNullException("providerName");

            if (string.IsNullOrEmpty(searchTerms))
                throw new ArgumentNullException("searchTerms");

            var searchQuery = new OpenSearchQuery()
            {
                StartIndex = pageIndex,
                Count = pageSize,
                SearchTerms = searchTerms
            };
            var atomResult = new OpenSearchAtomResult();
            ((IOpenSearchProvider)Providers[providerName]).Search(ref searchQuery, out atomResult);
            atomResult.Title = Providers[providerName].Title;
            return atomResult;
        }

        public IEnumerable<OpenSearchSuggestion> Suggest(string searchTerms, int? count = 20)
        {
            var suggestions = new List<OpenSearchSuggestion>();
            foreach (var key in Providers.Keys)
            {
                if (Providers[key].SupportSuggestion)
                {
                    try
                    {
                        var result = Providers[key].Suggest(searchTerms, count.Value);
                        if (result != null)
                            suggestions.AddRange(result);
                    }
                    catch { continue; }
                }
            }
            var comparer = new OpenSearchSuggestionComparer();
            if (suggestions.Count > 0)
                return suggestions.OrderBy(r => r.SearchTerms).Distinct(comparer).Take(count.Value);
            else
                return suggestions;
        }

        public IEnumerable<OpenSearchAtomResult> SearchAll(string searchTerms, string defaultProvider, int pageIndex, int pageSize)
        {
            var resultSet = new List<OpenSearchAtomResult>();
            var _default = defaultProvider;
            
            if (string.IsNullOrEmpty(defaultProvider) && Providers.Count > 0)
                _default = Providers.First().Key;

            foreach (var key in Providers.Keys)
            {
                try
                {
                    var _result = Search(key, searchTerms, key.Equals(_default, StringComparison.OrdinalIgnoreCase) ? pageIndex : 1, pageSize);
                    _result.ID = key;
                    resultSet.Add(_result);
                }
                catch(Exception e)
                {
                    continue; 
                }
            }
            return resultSet;
        }
    }
}